﻿//
// Copyright (c) 2011 Canyala Innovation AB
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
// associated documentation files (the "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
// copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH 
// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Canyala.Lagoon.Engineering
{
    /// <summary>
    /// Represents a monetary quantity. [Fowler PoEAA]
    /// </summary>
    public struct Money
    {
        /*
        internal decimal _amount;
        internal Currency _currency;

        /// <summary>
        /// Represents an Empty Money [Wolf NullObject]
        /// </summary>
        public static Money Empty;

        public Money()
        {
            _amount = 0;
            _currency = Currency.Empty;
        }

        /// <summary>
        /// Creates a Money with an Empty Unit.
        /// </summary>
        /// <param name="amount">The amount to initialize the quantity to.</param>
        public Money(decimal amount)
        {
            _amount = amount;
            _currency = Currency.Empty;
        }

        /// <summary>
        /// Creates a Money of a specific Currency.
        /// </summary>
        /// <param name="amount">The amount to initialize the quantity to.</param>
        /// <param name="unit">The unit the quantity represents.</param>
        public Money(decimal amount, Currency currency)
        {
            _amount = amount;
            _currency = currency;
        }

        /// <summary>
        /// Provides the Currency of the Money.
        /// </summary>
        public Currency Currency { get { return _currency; } }

        /// <summary>
        /// Converts the Money into a string.
        /// </summary>
        /// <returns>A string representing the Money.</returns>
        public override string ToString()
        {
            return String.Format("{0} {2}", _amount, Currency.Symbol);
        }

        /// <summary>
        /// Allows decimals to be assigned to Quantities.
        /// </summary>
        /// <param name="amount">The amount to assign to the Money.</param>
        /// <returns>The quantity.</returns>
        public static implicit operator Money(decimal amount)
        {
            return new Money(amount);
        }

        /// <summary>
        /// Allows strings to be assigned to Quantities.
        /// </summary>
        /// <param name="amount">The amount to assign to the Money.</param>
        /// <returns>The quantity.</returns>
        public static implicit operator Money(string text)
        {
            return Parse(text);
        }

        /// <summary>
        /// Adds two Quantities.
        /// </summary>
        /// <param name="a">The left hand side quantity.</param>
        /// <param name="b">The right hand side quantity.</param>
        /// <returns>The quantity sum.</returns>
        public static Money operator+(Money a, Money b)
        {
            return new Money(a._amount + b._amount, _currency.FromInference(a._unit, b._unit));
        }

        /// <summary>

        /// <summary>
        /// Subtracts a Money from a Money
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Money operator-(Money a, Money b)
        {
            return new Money(a._amount - b._amount, Unit.Resolve(a._unit, b._unit, Operator.Subtract));  
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Money operator*(Money a, Money b)
        {
            return new Money(a._amount * b._amount, Unit.Resolve(a._unit, b._unit, Operator.Multiply));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Money operator/(Money a, Money b)
        {
            return new Money(a._amount / b._amount, Unit.Resolve(a._unit, b._unit, Operator.Divide));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(Money a, Money b)
        {
            return a._amount == b._amount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(Money a, Money b)
        {
            return a._amount != b._amount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator >=(Money a, Money b)
        {
            return a._amount >= b._amount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator <=(Money a, Money b)
        {
            return a._amount <= b._amount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator >(Money a, Money b)
        {
            return a._amount > b._amount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator <(Money a, Money b)
        {
            return a._amount < b._amount;
        }

        private static Regex parseTokenizer = new Regex(@"([^\s]+)\s+([^\s]+)", RegexOptions.Compiled);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Money Parse(string s)
        {
            Match m = parseTokenizer.Match(s);
            return new Money(Decimal.Parse(m.Groups[1].Value), Prefix.Extract(m.Groups[2].Value), Unit.Extract(m.Groups[2].Value));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="a"></param>
        /// <returns></returns>
        public static bool TryParse(string s, out Money a)
        {
            decimal d;
            if (Decimal.TryParse(s, out d))
            {
                a = new Money( d );
                return true;
            }
            else
            {
                a = new Money(0);
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if (obj.GetType() != typeof(Money))
                return false;

            Money q = (Money) obj;
            if (q._amount != _amount)
                return false;

            if (q._currency != _currency)
                return false;

            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }
         */
    }
}
